package com.hebada.service;

import com.hebada.converter.PhotoConverter;
import com.hebada.domain.Photo;
import com.hebada.repository.PhotoJpaRepository;
import com.hebada.web.vo.request.PhotoSearchRequest;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;
import java.util.List;
import java.util.Map;

/**
 * Created by paddy.luo on 2017/9/19.
 */
@Service
public class PhotoService {

    @Autowired
    private PhotoJpaRepository photoJpaRepository;
    @Autowired
    private PhotoConverter photoConverter;

    public Photo get(long id) {
        return photoJpaRepository.findOne(id);
    }

    @Transactional
    public void save(List<Photo> photoList) {
        if (CollectionUtils.isEmpty(photoList)) return;
        photoJpaRepository.save(photoList);
    }

    @Transactional
    public void update(long id, Photo photo) {
        photoJpaRepository.save(photoConverter.convertToPhoto(this.get(id), photo));
    }

    @Transactional
    public void delete(long id) {
        photoJpaRepository.delete(id);
    }

    public Page<Photo> findPhotoListByCatalogId(long catalogId, int currentPage, int pageSize) {
        return photoJpaRepository.findByCatalogId(catalogId, new PageRequest(currentPage, pageSize));
    }

    public List<Photo> findPhotoListByProductId(long productId) {
        return photoJpaRepository.findByProductIdOrderByIdAsc(productId);
    }

    public List<Photo> findPhotoListByProductIds(List<Long> productIds) {
        if (CollectionUtils.isEmpty(productIds)) return null;
        return photoJpaRepository.findAll(where(productIds));
    }

    public Page<Photo> findPhotoListAll(int currentPage, int pageSize) {
        return photoJpaRepository.findAll(new PageRequest(currentPage, pageSize));
    }

    public Page<Photo> findPhotoList(Map<String, Object> params, int currentPage, int pageSize) {
        return photoJpaRepository.findAll(where(params), new PageRequest(currentPage, pageSize));
    }

    private Specification<Photo> where(final Map<String, Object> params) {
        return new Specification<Photo>() {

            @Override
            public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
                Predicate predicates = cb.conjunction();
                String photoName = String.valueOf(params.get(PhotoSearchRequest.PHOTO_NAME_KEY));
                if (StringUtils.hasLength(photoName))
                    predicates.getExpressions().add(cb.like(root.get("name"), "%" + photoName + "%"));
                if ((Boolean) params.get(PhotoSearchRequest.HAS_PRODUCT_PARAM)) {
                    Object o = params.get(PhotoSearchRequest.PRODUCT_KEY);
                    if (o != null)
                        cb.in(root.get("productId").in((List) o));
                    else
                        predicates.getExpressions().add(cb.isNull(root.get("productId")));
                }
                if ((Boolean) params.get(PhotoSearchRequest.HAS_CATALOG_PARAM)) {
                    Object o = params.get(PhotoSearchRequest.CATALOG_KEY);
                    if (o != null)
                        cb.in(root.get("catalogId").in((List) o));
                    else
                        predicates.getExpressions().add(cb.isNull(root.get("catalogId")));
                }
                query.orderBy(cb.desc(root.get("id")));
                return predicates;
            }
        };
    }

    private Specification<Photo> where(final List<Long> productIds) {
        return new Specification<Photo>() {

            @Override
            public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
                Predicate predicates = cb.conjunction();
                if (CollectionUtils.isNotEmpty(productIds))
                    cb.in(root.get("productId").in(productIds));
                query.orderBy(cb.desc(root.get("id")));
                return predicates;
            }
        };
    }
}
